﻿using HalconDotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace DetectApp.Display;

public class Rectangle2Control : ROIControl
{
    private readonly Canvas _canvas;
    private readonly List<Shape> _docEllipse = new();
    private readonly int _initHeight = 120;
    private readonly int _initWidth = 200;
    private int _docDiameter = 0;
    private bool _isMove;
    private bool _isRotate;
    private bool _isSCale1;
    private bool _isSCale2;
    private bool _isSCale3;
    private bool _isSCale4;
    private Polygon _rectangle2;
    private double _rotateAngle;
    private Point _startPoint;
    private double _startTopLeft;
    private double _startTopUp;

    public Rectangle2Control(Canvas canvas, Color color)
    {
        _canvas = canvas;
        _canvas.MouseMove += Canvas_MouseMove;
        _rectangle2 = new()
        {
            Fill = new SolidColorBrush(Colors.Red) { Opacity = 0.1 },
            Stroke = new SolidColorBrush(color),
            StrokeThickness = 0.3,
            Points = new PointCollection
                        {
                            new Point { X = 0, Y = 0 },
                            new Point { X = _initWidth*K,Y=0 },
                            new Point { X = _initWidth*K, Y = _initHeight*K},
                            new Point { X = 0,Y=_initHeight * K},
                        },
        };
        _rectangle2.MouseEnter += (sender, e) =>
        {
            UpdateEllipse(_rectangle2, _canvas);
        };
        _rectangle2.MouseLeftButtonDown += Rectangle2_MouseLeftButtonDown;
        Canvas.SetLeft(_rectangle2, _canvas.ActualWidth / 2 - _initWidth * K / 2);
        Canvas.SetTop(_rectangle2, _canvas.ActualHeight / 2 - _initHeight * K / 2);
        _canvas.Children.Add(_rectangle2);
        ROIChange?.Invoke(this, EventArgs.Empty);
    }

    double []_lenght=new double[2];
    public Rectangle2Control(Canvas canvas, Point p,double[] len, Color color)
    {
        _canvas = canvas;
        _lenght= len;
        _canvas.MouseMove += Canvas_MouseMove;
       
            _rectangle2 = new()
            {
                Fill = new SolidColorBrush(Colors.Transparent) { Opacity = 1 },
                Stroke = new SolidColorBrush(color),
                StrokeThickness = 3,
                Points = new PointCollection
                        {
                            new Point { X = p.X-_lenght[0], Y = p.Y-_lenght[1] },
                            new Point { X = p.X+_lenght[0],Y=p.Y-_lenght[1] },
                            new Point { X= p.X+_lenght[0],Y=p.Y+_lenght[1]},
                            new Point { X = p.X-_lenght[0], Y = p.Y+_lenght[1]},
                        },
            };
       
        _rectangle2.MouseEnter += (sender, e) =>
        {
            UpdateEllipse(_rectangle2, _canvas);
        };
        _rectangle2.MouseLeftButtonDown += Rectangle2_MouseLeftButtonDown;
        // Canvas.SetLeft(_rectangle2, _canvas.ActualWidth / 2 - _initWidth * K / 2);
        // Canvas.SetTop(_rectangle2, _canvas.ActualHeight / 2 - _initHeight * K / 2);
        _canvas.Children.Add(_rectangle2);
        ROIChange?.Invoke(this, EventArgs.Empty);
    }
    public Rectangle2Control(Canvas canvas, ROIParam rOIParam)
    {
        _canvas = canvas;
        _canvas.MouseMove += Canvas_MouseMove;
        _rectangle2 = new()
        {
            Fill = new SolidColorBrush(Colors.Red) { Opacity = 0.1 },
            Stroke = new SolidColorBrush(Colors.Blue),
            StrokeThickness = 0.3,
            Points = new PointCollection
                        {
                            rOIParam.Point1,
                            rOIParam.Point2,
                            rOIParam.Point3,
                            rOIParam.Point4,
                        },
        };
        _rectangle2.MouseEnter += (sender, e) =>
        {
            UpdateEllipse(_rectangle2, _canvas);
        };
        _rectangle2.MouseLeftButtonDown += Rectangle2_MouseLeftButtonDown;
        Canvas.SetLeft(_rectangle2, rOIParam.Left);
        Canvas.SetTop(_rectangle2, rOIParam.Top);
        _canvas.Children.Add(_rectangle2);
        ROIChange?.Invoke(this, EventArgs.Empty);
    }

    public double K { get => _canvas.ActualWidth / 500.0; }

    public static string RotateAngle(double XRotation, double YRotation, double ARotate, double XBefore, double YBefore, ref double XAfter, ref double YAfter)
    {
        try
        {
            double Rad = 0;
            Rad = ARotate * Math.PI / 180;
            XAfter = (XBefore - XRotation) * Math.Cos(Rad) - (YBefore - YRotation) * Math.Sin(Rad) + XRotation;
            YAfter = (XBefore - XRotation) * Math.Sin(Rad) + (YBefore - YRotation) * Math.Cos(Rad) + YRotation;
            return "OK";
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }

    public override ROIParam GetParam()
    {
        ROIParam roi = new() { ROIType = ROIType.无 };
        roi.ROIType = ROIType.矩形;
        roi.Point1 = _rectangle2.Points[0];
        roi.Point2 = _rectangle2.Points[1];
        roi.Point3 = _rectangle2.Points[2];
        roi.Point4 = _rectangle2.Points[3];
        roi.Left = Canvas.GetLeft(_rectangle2);
        roi.Top = Canvas.GetTop(_rectangle2);
        return roi;
    }

    public override HRegion? GetRegion()
    {
        var point1 = _rectangle2.TranslatePoint(_rectangle2.Points[0], _canvas);
        var point2 = _rectangle2.TranslatePoint(_rectangle2.Points[1], _canvas);
        var point3 = _rectangle2.TranslatePoint(_rectangle2.Points[2], _canvas);
        var point4 = _rectangle2.TranslatePoint(_rectangle2.Points[3], _canvas);
        double row = (point1.Y + point3.Y) / 2;
        double col = (point1.X + point3.X) / 2;
        HOperatorSet.DistancePp(point1.Y, point1.X, point2.Y, point2.X, out HTuple len1);
        len1 /= 2;
        HOperatorSet.DistancePp(point1.Y, point1.X, point4.Y, point4.X, out HTuple len2);
        len2 /= 2;
        HOperatorSet.AngleLx(point1.Y, point1.X, point2.Y, point2.X, out HTuple angle);

        HRegion region = new();
        region.GenRectangle2(row, col, angle.D, len1.D, len2.D);
        return region;
    }

    public override ROIInfo GetROI()
    {
        ROIInfo roi = new() { ROIType = ROIType.无 };
        var point1 = _rectangle2.TranslatePoint(_rectangle2.Points[0], _canvas);
        var point2 = _rectangle2.TranslatePoint(_rectangle2.Points[1], _canvas);
        var point3 = _rectangle2.TranslatePoint(_rectangle2.Points[2], _canvas);
        var point4 = _rectangle2.TranslatePoint(_rectangle2.Points[3], _canvas);
        roi.rect_p1 = point1;
        roi.rect_p2 = point2;
        roi.rect_p3 = point3;
        roi.rect_p4 = point4;
        double row = (point1.Y + point3.Y) / 2;
        double col = (point1.X + point3.X) / 2;
        HOperatorSet.DistancePp(point1.Y, point1.X, point2.Y, point2.X, out HTuple len1);
        len1 /= 2;
        HOperatorSet.DistancePp(point1.Y, point1.X, point4.Y, point4.X, out HTuple len2);
        len2 /= 2;
        HOperatorSet.AngleLx(point1.Y, point1.X, point2.Y, point2.X, out HTuple angle);

        roi.ROIType = ROIType.矩形;
        roi.len1 = len1.D;
        roi.len2 = len2.D;
        roi.phi = angle.D;
        roi.RectX = col;
        roi.RectY = row;
        roi.CenterPoint1 = new Point((point1.X + point4.X) / 2, (point1.Y + point4.Y) / 2);
        roi.CenterPoint2 = new Point((point2.X + point3.X) / 2, (point2.Y + point3.Y) / 2);

        Point circlePoint1 = new Point((point1.X + point4.X) / 2, (point1.Y + point4.Y) / 2); Point circlePoint2 = new((point1.X + point2.X) / 2, (point1.Y + point2.Y) / 2);
        Point circlePoint3 = new Point((point2.X + point3.X) / 2, (point2.Y + point3.Y) / 2);

        double radius = 0;
        Point circleCenter = tcircle(circlePoint1, circlePoint2, circlePoint3, ref radius);

        if (radius > 0)
        {
            double endAngle = -Math.Atan2((circlePoint1.Y - circleCenter.Y), (circlePoint1.X - circleCenter.X));
            double startAngle = -Math.Atan2(circlePoint3.Y - circleCenter.Y, circlePoint3.X - circleCenter.X);
            roi.circleRadius = radius; roi.CircleCenter = circleCenter; roi.rectStartPhi = startAngle; roi.rectEndPhi = endAngle;
        }

        return roi;
    }

    public override void Remove()
    {
        _canvas.Children.Remove(_rectangle2);
    }

    private void Canvas_MouseMove(object sender, MouseEventArgs e)
    {
        if (Mouse.LeftButton == MouseButtonState.Released)
        {
            _isMove = false; _isSCale1 = false; _isSCale2 = false; _isSCale3 = false; _isSCale4 = false; _isRotate = false;
        }
        if (!_isSCale1 & !_isSCale2 & !_isSCale3 & !_isSCale4 & !_isMove & !_isRotate)
        {
            bool isClear = true;
            if (_rectangle2.IsMouseOver == true) { isClear = false; }
            foreach (var rect in _docEllipse)
            {
                if (rect.IsMouseOver)
                {
                    isClear = false;
                    break;
                }
            }
            if (isClear)
            {
                _docEllipse.ForEach(e => { _canvas.Children.Remove(e); });
                _docEllipse.Clear();
            };
        }
        if (_isMove)
        {
            Point curPoint = Mouse.GetPosition(_canvas);
            var rPoint = curPoint - _startPoint;
            var p = new Point(rPoint.X + _recStart.X, rPoint.Y + _recStart.Y);
            _rectangle2.Points = new PointCollection()
            {
                 new Point { X = p.X-_lenght[0], Y = p.Y-_lenght[1] },
                            new Point { X = p.X+_lenght[0],Y=p.Y-_lenght[1] },
                            new Point { X= p.X+_lenght[0],Y=p.Y+_lenght[1]},
                            new Point { X = p.X-_lenght[0], Y = p.Y+_lenght[1]},
            };
            //  Canvas.SetLeft(_rectangle2, _startTopLeft + rPoint.X);
            //Canvas.SetTop(_rectangle2, _startTopUp + rPoint.Y);
            UpdateEllipse(_rectangle2, _canvas);
            ROIChange?.Invoke(this, EventArgs.Empty);
        }
        if (_isSCale1)
        {
            //Point endPoint = Mouse.GetPosition(_canvas);
            //var p2 = _rectangle2.Points[2];
            //double angle = _rotateAngle;
            //_rectangle2.Points[0] = _canvas.TranslatePoint(endPoint, _rectangle2);
            //var p0 = _rectangle2.Points[0];

            //double angle1 = Math.Atan2(p2.Y - p0.Y, p2.X - p0.X);
            //double centerx = (p0.X + p2.X) / 2;
            //double centery = (p0.Y + p2.Y) / 2;
            //double angle2 = -2 * (angle1 - angle);

            //double x = (p2.X - centerx) * Math.Cos(angle2) - (p2.Y - centery) * Math.Sin(angle2) + centerx;
            //double y = (p2.X - centerx) * Math.Sin(angle2) + (p2.Y - centery) * Math.Cos(angle2) + centery;
            //_rectangle2.Points[1] = new Point(x, y);

            //angle2 = -Math.PI + angle2;
            //x = (p2.X - centerx) * Math.Cos(angle2) - (p2.Y - centery) * Math.Sin(angle2) + centerx;
            //y = (p2.X - centerx) * Math.Sin(angle2) + (p2.Y - centery) * Math.Cos(angle2) + centery;

            //_rectangle2.Points[3] = new Point(x, y);
            //UpdateEllipse(_rectangle2, _canvas);
            //ROIChange?.Invoke(this, EventArgs.Empty);
        }
        if (_isSCale2)
        {
            Point endPoint = Mouse.GetPosition(_canvas);
            var p3 = _rectangle2.Points[3];
            double angle = _rotateAngle;
            _rectangle2.Points[1] = _canvas.TranslatePoint(endPoint, _rectangle2);
            var p1 = _rectangle2.Points[1];

            double angle1 = Math.Atan2(p3.Y - p1.Y, p3.X - p1.X);
            double centerx = (p1.X + p3.X) / 2;
            double centery = (p1.Y + p3.Y) / 2;
            double angle2 = -2 * (angle1 - angle);

            double x = (p3.X - centerx) * Math.Cos(angle2) - (p3.Y - centery) * Math.Sin(angle2) + centerx;
            double y = (p3.X - centerx) * Math.Sin(angle2) + (p3.Y - centery) * Math.Cos(angle2) + centery;
            _rectangle2.Points[2] = new Point(x, y);

            angle2 = -Math.PI + angle2;
            x = (p3.X - centerx) * Math.Cos(angle2) - (p3.Y - centery) * Math.Sin(angle2) + centerx;
            y = (p3.X - centerx) * Math.Sin(angle2) + (p3.Y - centery) * Math.Cos(angle2) + centery;
            _rectangle2.Points[0] = new Point(x, y);

            UpdateEllipse(_rectangle2, _canvas);
            ROIChange?.Invoke(this, EventArgs.Empty);
        }
        if (_isSCale3)
        {
            //Point endPoint = Mouse.GetPosition(_canvas);
            //var p0 = _rectangle2.Points[0];
            //double angle = _rotateAngle;
            //_rectangle2.Points[2] = _canvas.TranslatePoint(endPoint, _rectangle2);
            //var p2 = _rectangle2.Points[2];

            //double angle1 = Math.Atan2(p2.Y - p0.Y, p2.X - p0.X);
            //double centerx = (p0.X + p2.X) / 2;
            //double centery = (p0.Y + p2.Y) / 2;
            //double angle2 = -2 * (angle1 - angle) + Math.PI;

            //double x = (p0.X - centerx) * Math.Cos(angle2) - (p0.Y - centery) * Math.Sin(angle2) + centerx;
            //double y = (p0.X - centerx) * Math.Sin(angle2) + (p0.Y - centery) * Math.Cos(angle2) + centery;
            //_rectangle2.Points[1] = new Point(x, y);

            //angle2 = -Math.PI + angle2;
            //x = (p0.X - centerx) * Math.Cos(angle2) - (p0.Y - centery) * Math.Sin(angle2) + centerx;
            //y = (p0.X - centerx) * Math.Sin(angle2) + (p0.Y - centery) * Math.Cos(angle2) + centery;
            //_rectangle2.Points[3] = new Point(x, y);

            //UpdateEllipse(_rectangle2, _canvas);
            //ROIChange?.Invoke(this, EventArgs.Empty);
        }
        if (_isSCale4)
        {
        //    Point endPoint = Mouse.GetPosition(_canvas);
        //    var p1 = _rectangle2.Points[1];
        //    double angle = _rotateAngle;

        //    _rectangle2.Points[3] = _canvas.TranslatePoint(endPoint, _rectangle2);
        //    var p3 = _rectangle2.Points[3];

        //    double angle1 = Math.Atan2(p3.Y - p1.Y, p3.X - p1.X);
        //    double centerx = (p1.X + p3.X) / 2;
        //    double centery = (p1.Y + p3.Y) / 2;
        //    double angle2 = -2 * (angle1 - angle) + Math.PI;

        //    double x = (p1.X - centerx) * Math.Cos(angle2) - (p1.Y - centery) * Math.Sin(angle2) + centerx;
        //    double y = (p1.X - centerx) * Math.Sin(angle2) + (p1.Y - centery) * Math.Cos(angle2) + centery;
        //    _rectangle2.Points[2] = new Point(x, y);

        //    angle2 = -Math.PI + angle2;
        //    x = (p1.X - centerx) * Math.Cos(angle2) - (p1.Y - centery) * Math.Sin(angle2) + centerx;
        //    y = (p1.X - centerx) * Math.Sin(angle2) + (p1.Y - centery) * Math.Cos(angle2) + centery;

        //    _rectangle2.Points[0] = new Point(x, y);
        //    UpdateEllipse(_rectangle2, _canvas);
        //    ROIChange?.Invoke(this, EventArgs.Empty);
        //}
        //if (_isRotate)
        //{
        //    Point curPoint = Mouse.GetPosition(_canvas);
        //    var point1 = _rectangle2.TranslatePoint(_rectangle2.Points[0], _canvas);
        //    var point2 = _rectangle2.TranslatePoint(_rectangle2.Points[2], _canvas);
        //    double x = (point1.X + point2.X) / 2;
        //    double y = (point1.Y + point2.Y) / 2;
        //    var a = Math.Atan2(_startPoint.Y - y, _startPoint.X - x);
        //    var b = Math.Atan2(curPoint.Y - y, curPoint.X - x);
        //    double angle = 180 * (b - a) / Math.PI;

        //    UpdateRect2(_rectangle2, angle);
        //    UpdateEllipse(_rectangle2, _canvas);
        //    ROIChange?.Invoke(this, EventArgs.Empty);
        }
    }

    Point _recStart;
    private void Rectangle2_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _isMove = true;
        _startPoint = Mouse.GetPosition(_canvas);
        _startTopUp = Canvas.GetTop(_rectangle2);
        _startTopLeft = Canvas.GetLeft(_rectangle2);

        _recStart.X = (_rectangle2.Points[1].X - _rectangle2.Points[0].X) / 2 + _rectangle2.Points[0].X;

        _recStart.Y = (_rectangle2.Points[2].Y - _rectangle2.Points[0].Y) / 2 + _rectangle2.Points[0].Y;
    }

    private Point tcircle(Point pt1, Point pt2, Point pt3, ref double radius)
    {
        double x1 = pt1.X, x2 = pt2.X, x3 = pt3.X;
        double y1 = pt1.Y, y2 = pt2.Y, y3 = pt3.Y;
        double a = x1 - x2;
        double b = y1 - y2;
        double c = x1 - x3;
        double d = y1 - y3;
        double e = ((x1 * x1 - x2 * x2) + (y1 * y1 - y2 * y2)) / 2.0;
        double f = ((x1 * x1 - x3 * x3) + (y1 * y1 - y3 * y3)) / 2.0;
        double det = b * c - a * d;
        if (Math.Abs(det) < 1e-5)
        {
            radius = -1;
            return new Point(0, 0);
        }

        double x0 = -(d * e - b * f) / det;
        double y0 = -(a * f - c * e) / det;
        radius = Math.Sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
        return new Point(x0, y0);
    }

    private void UpdateEllipse(Polygon rectangle2, Canvas canvas)
    {
        // ROIChange?.Invoke(this, EventArgs.Empty);
        _docDiameter = (int)(5 * K);
        Brush fillBrush = new SolidColorBrush(Colors.Blue);
        double opacityK = 1;
        _docEllipse.ForEach(e => { canvas.Children.Remove(e); });
        _docEllipse.Clear();
        //左上角点
        Point point = rectangle2.TranslatePoint(rectangle2.Points[0], canvas);
        Ellipse rect1 = new() { Width = _docDiameter, Height = _docDiameter, Fill = fillBrush, Opacity = opacityK };
        Canvas.SetLeft(rect1, point.X - _docDiameter / 2);
        Canvas.SetTop(rect1, point.Y - _docDiameter / 2);
        canvas.Children.Add(rect1);
        _docEllipse.Add(rect1);
        rect1.MouseLeftButtonDown += (s, e) =>
        {
            _isSCale1 = true;
            _startPoint = Mouse.GetPosition(canvas);
            _rotateAngle = Math.Atan2(rectangle2.Points[2].Y - rectangle2.Points[3].Y, rectangle2.Points[2].X - rectangle2.Points[3].X);
        };
        rectangle2.MouseLeftButtonUp += (s, e) => { _isSCale1 = false; };
        //右上角点
        point = rectangle2.TranslatePoint(rectangle2.Points[1], canvas);
        Ellipse rect2 = new() { Height = _docDiameter, Width = _docDiameter, Fill = fillBrush, Opacity = opacityK };
        Canvas.SetLeft(rect2, point.X - _docDiameter / 2);
        Canvas.SetTop(rect2, point.Y - _docDiameter / 2);
        canvas.Children.Add(rect2);
        _docEllipse.Add(rect2);
        rect2.MouseLeftButtonDown += (s, e) =>
        {
            _isSCale2 = true;
            _startPoint = Mouse.GetPosition(canvas);
            _rotateAngle = Math.Atan2(rectangle2.Points[2].Y - rectangle2.Points[1].Y, rectangle2.Points[2].X - rectangle2.Points[1].X);
        };
        //右下角点位
        point = rectangle2.TranslatePoint(rectangle2.Points[2], canvas);
        Ellipse rect3 = new() { Width = _docDiameter, Height = _docDiameter, Fill = fillBrush, Opacity = opacityK };
        Canvas.SetLeft(rect3, point.X - _docDiameter / 2);
        Canvas.SetTop(rect3, point.Y - _docDiameter / 2);
        canvas.Children.Add(rect3);
        _docEllipse.Add(rect3);
        rect3.MouseLeftButtonDown += (s, e) =>
        {
            _isSCale3 = true;
            _startPoint = Mouse.GetPosition(canvas);
            _rotateAngle = Math.Atan2(rectangle2.Points[2].Y - rectangle2.Points[3].Y, rectangle2.Points[2].X - rectangle2.Points[3].X);
        };
        //左下角点位
        point = rectangle2.TranslatePoint(rectangle2.Points[3], canvas);
        Ellipse rect4 = new() { Height = _docDiameter, Width = _docDiameter, Fill = fillBrush, Opacity = opacityK };
        Canvas.SetLeft(rect4, point.X - _docDiameter / 2);
        Canvas.SetTop(rect4, point.Y - _docDiameter / 2);
        canvas.Children.Add(rect4);
        _docEllipse.Add(rect4);
        rect4.MouseLeftButtonDown += (s, e) =>
        {
            _isSCale4 = true;
            _startPoint = Mouse.GetPosition(canvas);
            _rotateAngle = Math.Atan2(rectangle2.Points[2].Y - rectangle2.Points[1].Y, rectangle2.Points[2].X - rectangle2.Points[1].X);
        };
        //旋转点位
        Point point1 = rectangle2.TranslatePoint(rectangle2.Points[1], canvas);
        Point point2 = rectangle2.TranslatePoint(rectangle2.Points[2], canvas);
        point = new Point() { X = (point1.X + point2.X) / 2, Y = (point1.Y + point2.Y) / 2 };
        Rectangle rect5 = new() { Height = _docDiameter, Width = _docDiameter * 2, Fill = fillBrush, Opacity = opacityK };
        double angle = Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
        rect5.RenderTransform = new RotateTransform(angle / Math.PI * 180 - 90);
        double dis = Math.Sqrt(5 * _docDiameter * _docDiameter) / 2f;
        Canvas.SetLeft(rect5, point.X - Math.Cos(angle - Math.PI / 2f) * dis);
        Canvas.SetTop(rect5, point.Y - Math.Sin(angle - Math.PI / 2f) * dis);
        canvas.Children.Add(rect5);
        _docEllipse.Add(rect5);
        rect5.MouseLeftButtonDown += (s, e) =>
        {
            _isRotate = true;
            _startPoint = Mouse.GetPosition(canvas);
            _rotateAngle = 0;
        };
    }

    private void UpdateRect2(Polygon polyline, double angle)
    {
        double ra = angle - _rotateAngle;
        double x = (polyline.Points[0].X + polyline.Points[2].X) / 2;
        double y = (polyline.Points[0].Y + polyline.Points[2].Y) / 2;
        Point center = new(x, y);
        double rx = 0, ry = 0;
        for (int i = 0; i < polyline.Points.Count; i++)
        {
            var p = polyline.Points[i];
            RotateAngle(center.X, center.Y, ra, p.X, p.Y, ref rx, ref ry);
            polyline.Points[i] = new Point(rx, ry);
        }
        _rotateAngle = angle;
    }
}